package com.zhike.service.messages.impl;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zhike.common.dto.ChatSessionMessageDTO;
import com.zhike.common.dto.GroupAtUserForSessionDTO;
import com.zhike.common.dto.GroupInfo4Cache;
import com.zhike.common.dto.GroupMember4Cache;
import com.zhike.common.enums.YesNoEnum;
import com.zhike.common.exception.ZkimException;
import com.zhike.common.model.ChatSession;
import com.zhike.common.repository.HistoryMessage;
import com.zhike.common.vo.ChatSessionVO;
import com.zhike.common.vo.UserInfo4Cache;
import com.zhike.mapper.messages.ChatSessionMapper;
import com.zhike.service.messages.IChatSessionService;
import com.zhike.utils.cache.GroupsInfoCacheProvider;
import com.zhike.utils.cache.GroupsMembersCacheProvider;
import com.zhike.utils.cache.UsersInfoCacheProvider;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class ChatSessionServiceImpl implements IChatSessionService {

    @Resource
    private ChatSessionMapper chatSessionMapper;

    @Autowired
    private GroupsInfoCacheProvider groupsInfoCacheProvider;

    @Autowired
    private UsersInfoCacheProvider usersInfoCacheProvider;

    @Autowired
    private GroupsMembersCacheProvider groupsMembersCacheProvider;

    public List<ChatSessionVO> queryUserChatSession(String uid) throws Exception {
        List<ChatSessionVO> list = chatSessionMapper.selectChatSession(uid);
        return list;
    }

    @Override
    public String updateUserChatSession(ChatSessionMessageDTO dto) {
        LambdaQueryWrapper<ChatSession> lqw = Wrappers.lambdaQuery();
        lqw.eq(ChatSession::getFromUid, dto.getFromUid());
        lqw.eq(ChatSession::getToUid, dto.getToUid());
        ChatSession entity = chatSessionMapper.selectOne(lqw);
        if (entity != null) {
            LambdaUpdateWrapper<ChatSession> luw = Wrappers.lambdaUpdate();
            luw.eq(ChatSession::getFromUid, dto.getFromUid());
            luw.eq(ChatSession::getToUid, dto.getToUid());
            luw.set(ChatSession::getLastMsg, dto.getLastMsg());
            luw.set(ChatSession::getLastTime, new Date());
            luw.set(ChatSession::getMsgType, dto.getMsgType());
            luw.set(ChatSession::getChatType, dto.getChatType());
            luw.set(ChatSession::getFp, dto.getFp());
            if (chatSessionMapper.update(entity, luw) > 0) {
                return entity.getSessionId();
            }
        } else {
            entity = new ChatSession();
            entity.setFromUid(dto.getFromUid());
            entity.setToUid(dto.getToUid());
            entity.setChatType(dto.getChatType());
            entity.setMsgType(dto.getMsgType());
            entity.setLastMsg(dto.getLastMsg());
            entity.setLastTime(new Date());
            entity.setGroupId(dto.getGroupId());
            entity.setSessionId(dto.getSessionId());
            entity.setFp(dto.getFp());
            if (chatSessionMapper.insert(entity) > 0) {
                return entity.getSessionId();
            }
        }
        return "";
    }

    @Override
    public String getSessionIdWithFriend(String fakeUid, String friendUid) {
        LambdaQueryWrapper<ChatSession> lqw = new LambdaQueryWrapper<>();
        ChatSession cs = chatSessionMapper.selectOne(lqw);
        return cs != null ? cs.getSessionId() : "";
    }

    @Override
    public boolean chatSessionTop(String sessionId, String fromUid, Integer action) {
        LambdaUpdateWrapper<ChatSession> luw = Wrappers.lambdaUpdate();
        luw.eq(ChatSession::getSessionId, sessionId);
        luw.eq(ChatSession::getFromUid, fromUid);
        luw.set(ChatSession::getIsTop, action);
        return chatSessionMapper.update(new ChatSession(), luw) > 0;
    }

    @Override
    public boolean deleteSession(String fromUid, String toUid, String toGid) {
        LambdaQueryWrapper<ChatSession> lqw = Wrappers.lambdaQuery();
        lqw.eq(ChatSession::getFromUid, fromUid);
        if (StringUtils.isNotBlank(toGid)) {
            lqw.eq(ChatSession::getGroupId, toGid);
        } else {
            lqw.eq(ChatSession::getToUid, toUid);
        }
        return chatSessionMapper.delete(lqw) > 0;
    }

    @Override
    public boolean deleteGroupAllSession(String groupId) {
        LambdaQueryWrapper<ChatSession> lqw = Wrappers.lambdaQuery();
        lqw.eq(ChatSession::getGroupId, groupId);
        return chatSessionMapper.delete(lqw) > 0;
    }

    @Override
    public boolean updateLastSession(HistoryMessage vo) {
        if (vo == null) {
            return false;
        }

        LambdaUpdateWrapper<ChatSession> luw = Wrappers.lambdaUpdate();
        luw.eq(ChatSession::getFromUid, vo.getSenderUid());
        luw.eq(ChatSession::getToUid, vo.getReceiver());
        luw
                .set(ChatSession::getChatType, vo.getChatType())
                .set(ChatSession::getMsgType, vo.getMsgType())
                .set(ChatSession::getLastMsg, vo.getContent())
                .set(ChatSession::getLastTime, vo.getTimestamp())
                .set(ChatSession::getSessionId, vo.getSessionId())
                .set(ChatSession::getFp, vo.getFp());
        return chatSessionMapper.update(new ChatSession(), luw) > 0;
    }

    @Override
    public ChatSession selectChatSession(String fakeUid, String friendUid) {
        LambdaQueryWrapper<ChatSession> lqw = Wrappers.lambdaQuery();
        lqw.eq(ChatSession::getFromUid, fakeUid);
        lqw.eq(ChatSession::getToUid, friendUid);
        return chatSessionMapper.selectOne(lqw);
    }

    @Override
    public ChatSession selectGroupSession(String fakeUid, String groupId) {
        LambdaQueryWrapper<ChatSession> lqw = Wrappers.lambdaQuery();
        lqw.eq(ChatSession::getFromUid, fakeUid);
        lqw.eq(ChatSession::getGroupId, groupId);
        return chatSessionMapper.selectOne(lqw);
    }

    @Override
    @Transactional()
    public String createSession(String fromUid, String targetId) {
        UserInfo4Cache uc = usersInfoCacheProvider.get(targetId);
        if (uc != null) {
            String sessionId = "";
            ChatSession cs1 = this.selectChatSession(fromUid, targetId);
            ChatSession cs2 = this.selectChatSession(targetId, fromUid);
            if (cs1 == null && cs2 == null) {
                sessionId = IdUtil.getSnowflakeNextIdStr();

                cs1 = new ChatSession();
                cs1.setFromUid(fromUid);
                cs1.setToUid(targetId);
                cs1.setChatType("0");
                cs1.setLastTime(new Date());
                cs1.setSessionId(sessionId);

                cs2 = ObjectUtil.clone(cs1);
                cs2.setFromUid(targetId);
                cs2.setToUid(fromUid);
                chatSessionMapper.insert(cs1);
                chatSessionMapper.insert(cs2);
            } else {
                if (cs1 == null) {
                    cs1 = new ChatSession();
                    cs1.setFromUid(fromUid);
                    cs1.setToUid(targetId);
                    cs1.setChatType("0");
                    cs1.setLastTime(new Date());
                    cs1.setSessionId(cs2.getSessionId());
                    chatSessionMapper.insert(cs1);
                    sessionId = cs2.getSessionId();
                } else if (cs2 == null) {
                    cs2 = new ChatSession();
                    cs2.setFromUid(targetId);
                    cs2.setToUid(fromUid);
                    cs2.setChatType("0");
                    cs2.setLastTime(new Date());
                    cs2.setSessionId(cs1.getSessionId());
                    chatSessionMapper.insert(cs2);
                    sessionId = cs1.getSessionId();
                }else{
                    sessionId = cs1.getSessionId();//或cs2.getSessionId();应该是一致的
                }
            }

            log.debug("成功创建单聊会话 sessionId: {}", sessionId);
            return sessionId;
        }

        GroupInfo4Cache gc = groupsInfoCacheProvider.get(targetId);
        if (gc != null) {
            ChatSession cs = this.selectGroupSession(fromUid, targetId);
            if (cs != null) {
                return cs.getSessionId();
            } else {
                ChatSession entity = new ChatSession();
                entity.setFromUid(fromUid);
                entity.setGroupId(targetId);
                entity.setChatType("2");// 群聊
                entity.setLastTime(new Date());
                List<ChatSession> csList = this.selectGroupSession(targetId);
                if (csList.size() > 0) {
                    String sessionId = csList.get(0).getSessionId();
                    entity.setSessionId(sessionId);
                } else {
                    entity.setSessionId(IdUtil.getSnowflakeNextIdStr());
                }
                if (chatSessionMapper.insert(entity) > 0) {
                    log.debug("成功创建群聊聊会话 sessionId: {}", entity.getSessionId());
                    return entity.getSessionId();
                }
            }

        }

        return null;
    }

    @Override
    public boolean createGroupSession(HistoryMessage hm, String groupName, String lastMsgUid) {
        ChatSession cs = this.selectGroupSession(hm.getSenderUid(), hm.getGroupId());
        if (cs == null) {
            ChatSession entity = new ChatSession();
            entity.setFromUid(hm.getSenderUid());
            entity.setToUid("");
            entity.setGroupId(hm.getGroupId());
            entity.setChatType("2");
            entity.setMsgType(String.valueOf(hm.getMsgType()));
            entity.setLastMsg(hm.getContent());
            entity.setLastTime(new Date());
            entity.setFp(hm.getFp());
            entity.setGroupName(groupName);
            entity.setSessionId(hm.getSessionId());
            entity.setLastMsgUid(lastMsgUid);
            return chatSessionMapper.insert(entity) > 0;
        }
        return false;
    }

    @Override
    public boolean createGroupSession2(HistoryMessage hm, String groupName, String lastMsgUid, String memberId) {
        ChatSession entity = new ChatSession();
        entity.setFromUid(memberId);
        entity.setToUid("");
        entity.setGroupId(hm.getGroupId());
        entity.setChatType("2");
        entity.setMsgType(String.valueOf(hm.getMsgType()));
        entity.setLastMsg(hm.getContent());
        entity.setLastTime(new Date());
        entity.setFp(hm.getFp());
        entity.setGroupName(groupName);
        entity.setSessionId(hm.getSessionId());
        entity.setLastMsgUid(lastMsgUid);
        return chatSessionMapper.insert(entity) > 0;
    }

    @Override
    public Boolean updateGroupSession(HistoryMessage vo, String groupName, String lastMsgUid) {
        LambdaUpdateWrapper<ChatSession> luw = Wrappers.lambdaUpdate();
        luw.eq(ChatSession::getGroupId, vo.getGroupId());
        luw.set(ChatSession::getLastMsg, vo.getContent());
        luw.set(ChatSession::getMsgType, vo.getMsgType());
        luw.set(ChatSession::getChatType, vo.getChatType());
        luw.set(ChatSession::getFp, vo.getFp());
        luw.set(ChatSession::getLastTime, new Date());
        luw.set(ChatSession::getLastMsgUid, lastMsgUid);
        luw.set(ChatSession::getGroupName, groupName);
        return chatSessionMapper.update(new ChatSession(), luw) > 0;
    }

    @Override
    public Boolean updateGroupSession2(HistoryMessage vo, Long id, String groupName, String lastMsgUid) {
        LambdaUpdateWrapper<ChatSession> luw = Wrappers.lambdaUpdate();
        luw.eq(ChatSession::getId, id);
        luw.set(ChatSession::getLastMsg, vo.getContent());
        luw.set(ChatSession::getMsgType, vo.getMsgType());
        luw.set(ChatSession::getChatType, vo.getChatType());
        luw.set(ChatSession::getFp, vo.getFp());
        luw.set(ChatSession::getLastTime, new Date());
        luw.set(ChatSession::getLastMsgUid, lastMsgUid);
        luw.set(ChatSession::getGroupName, groupName);
        return chatSessionMapper.update(new ChatSession(), luw) > 0;
    }

    @Override
    public List<ChatSession> selectGroupSession(String groupId) {
        LambdaQueryWrapper<ChatSession> lqw = Wrappers.lambdaQuery();
        lqw.eq(ChatSession::getGroupId, groupId);
        return chatSessionMapper.selectList(lqw);
    }

    /**
     * 初始化群会话（创建群时）
     * 为群成员初始化群会话
     * 
     * @return
     */
    @Transactional
    public String initGroupSession(String groupId) {
        ConcurrentHashMap<String, GroupMember4Cache> members = groupsMembersCacheProvider.get(groupId);
        Iterator<String> membersToSend = members.keySet().iterator();

        String sessionId = IdUtil.getSnowflakeNextIdStr();
        while (membersToSend.hasNext()) {
            final String uid = (String) membersToSend.next();
            ChatSession entity = new ChatSession();
            entity.setFromUid(uid);
            entity.setGroupId(groupId);
            entity.setChatType("2");// 群聊
            entity.setMsgType("0");
            entity.setLastTime(new Date());
            entity.setSessionId(sessionId);
            chatSessionMapper.insert(entity);
        }
        return sessionId;
    }

    /**
     * 邀请新成员时初始化
     */
    @Override
    public void initGroupMemberSession(String groupId, String uid) {
        LambdaQueryWrapper<ChatSession> lqw = Wrappers.lambdaQuery();
        lqw.eq(ChatSession::getGroupId, groupId);
        lqw.last("LIMIT 1");
        ChatSession cs = chatSessionMapper.selectList(lqw).get(0);
        if (cs == null) {
            throw new ZkimException("群:" + groupId + " 会话不存在");
        }

        ChatSession entity = new ChatSession();
        entity.setFromUid(uid);
        entity.setGroupId(groupId);
        entity.setChatType("2");// 群聊
        entity.setMsgType("0");
        entity.setLastTime(new Date());
        entity.setSessionId(cs.getSessionId());
        chatSessionMapper.insert(entity);
    }

    @Override
    public void updateNotifyCount(String groupId, List<String> userIds, int count) {
        LambdaUpdateWrapper<ChatSession> luw = new LambdaUpdateWrapper<>();
        luw.eq(ChatSession::getGroupId, groupId);
        luw.in(ChatSession::getFromUid, userIds);
        luw.set(ChatSession::getNotifyCount, count);
        chatSessionMapper.update(new ChatSession(), luw);
    }

    @Override
    public Boolean nodisturb(String sessionId, String uid, Integer action) {
        LambdaUpdateWrapper<ChatSession> luw = new LambdaUpdateWrapper<>();
        luw.eq(ChatSession::getSessionId, sessionId);
        luw.eq(ChatSession::getFromUid, uid);
        luw.set(ChatSession::getNodisturb, action);
        return chatSessionMapper.update(new ChatSession(), luw) > 0;
    }

    @Override
    public Boolean updateSessionAt(GroupAtUserForSessionDTO dto, Integer at) {
        LambdaUpdateWrapper<ChatSession> luw = new LambdaUpdateWrapper<>();
        luw.eq(ChatSession::getGroupId, dto.getGroupId());
        if (!dto.getIsAll().equals(YesNoEnum.YES.getValue())) {
            luw.in(ChatSession::getFromUid, dto.getUserIds());
        }
        luw.set(ChatSession::getAt, at);
        return chatSessionMapper.update(new ChatSession(), luw) > 0;
    }
}
